package np13;

import java.util.LinkedList;

import np13.ferry.Ferry;
import np13.ferry.Pier;

/**
 * Represents a queue of slimes. Note that each queue is connected to a pier and
 * each pier is connected to a Ferry.
 */
public class SlimeQueue {

	/**
	 * The capacity of the connected Ferry. This field is used to ensure that
	 * the Ferry only embarks on the sailing trip if there are at least
	 * targetSize slimes enqueued.
	 */
	private final int targetSize;

	/**
	 * Represents the queue.
	 */
	private final LinkedList<Slime> content = new LinkedList<Slime>();

	/**
	 * The connected pier.
	 */
	private final Pier pier;

	/**
	 * 
	 */
	// private FunafituMonad myMonad;

	/**
	 * Creates a queue of slimes.
	 * 
	 * @param pier
	 *            The connected pier.
	 * @param targetSize
	 *            The capacity of the Ferry which is connected to the pier.
	 */
	public SlimeQueue(Pier pier, int targetSize) {
		this.pier = pier;
		this.targetSize = targetSize;
	}

	/**
	 * Removes the first enqueued slime from the queue.
	 * 
	 * @return The first enqueued slime.
	 */
	public synchronized Slime dequeueSlime() {
		assert !content.isEmpty();
		return content.pop();
	}

	/**
	 * Enqueues a slime into the queue. This method is synchronized.
	 * 
	 * @param slime
	 *            The slime to enqueue.
	 */
	public synchronized void enqueueSlime(Slime slime) {
		content.add(slime);
	}

	/**
	 * Returns the actual size of the this {@link SlimeQueue}. This method is
	 * synchronized.
	 * 
	 * @return The amount of slimes enqueued.
	 */
	public synchronized int getCurrentSize() {
		return content.size();
	}

	/**
	 * Returns the connected {@link Pier}. This is never changed so it does not
	 * need synchronized.
	 * 
	 * @return The connected pier.
	 */
	public Pier getPier() {
		return pier;
	}

	/**
	 * Returns the capacity of the connected {@link Ferry}. This is never
	 * changed so it does not need synchronized.
	 * 
	 * @return The capacity of the connected Ferry.
	 */
	public int getTargetSize() {
		return targetSize;
	}

	/**
	 * Retruns a boolean if this {@SlimeQueue} is empty. This
	 * method is synchronized.
	 * 
	 * @return Returns true if Queue contains no elements.
	 */
	public synchronized boolean isEmpy() {
		return content.isEmpty();
	}

	/**
	 * This method adds Slimes into the {@link SlimeQueue} until it reaches the
	 * targetSize.
	 * 
	 * @param slime
	 *            The Slime to be added in Queue.
	 * @return Returns true if Slime gets added into the Queue.
	 */
	public synchronized boolean loadSlime(Slime slime) {
		if (content.size() >= targetSize) {
			return false;
		} else {
			content.add(slime);
			return true;
		}
	}

	/**
	 * Retrieves, but does not remove, the last element of this
	 * {@link SlimeQueue}, or returns null if {@link SlimeQueue} is empty. This
	 * method is synchronized.
	 * 
	 * @return the last Slime in the Queue or null if empty.
	 */
	public synchronized Slime peekLastSlime() {
		return content.peekLast();
	}

	/**
	 * Adds a slime at the beginning of this {@link SlimeQueue}. This method is
	 * synchronized.
	 * 
	 * @param slime
	 *            The slime to be added.
	 */
	public synchronized void pushSlime(Slime slime) {
		content.push(slime);
	}
}
